﻿using System;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Net;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows.Forms;
using AndreasJohansson.Win32.Shell;
using CloudShot.Properties;
using CloudShot.Utils;

namespace CloudShot.ImageStorages
{
	class DropboxImageStorage : FileStorageBase, IImageStorage
	{
		private const int TRY_UPLOAD_COUNT = 10;
		private const int UPLOAD_SLEEP_TIME = 500;

		private long _userId = 0;

		public override Image Logo { get { return Resources.dropbox; } }
		public override string Name { get { return "Dropbox"; } }

		public override bool SupportsSaveToFileSystem
		{
			get { return true; }
		}

		public DropboxImageStorage(string root)
			: base(root)
		{
		}

		public override bool IsShotInStorege(ShotInfo shotInfo)
		{
			return IsShotInStorege(shotInfo, true);
		}

		public bool IsShotInStorege(ShotInfo shotInfo, bool checkInFileSystem)
		{
			if (shotInfo == null)
				return false;

			if (checkInFileSystem)
			{
				return File.Exists(shotInfo.Path);
			}
			else
			{
				if (shotInfo.Url == null)
					return false;

				if (shotInfo.Url.IsFile)
					return File.Exists(shotInfo.Path);

				return RemoteFileExists(shotInfo.Url.AbsoluteUri);
			}
		}

		protected override Uri GetPublicUrl(string path)
		{
			if (_userId == 0)
			{
				var menu = new DropboxContextMenu();
				menu.CopyPublicLink(path);
				string result = Clipboard.GetText();

				_userId = GetUserId(result);

				if (_userId == 0)
					return new Uri(path);

				return new Uri(result);
			}

			path = path.Replace(DropboxUtils.DropboxPublicFolder, "").Trim('/', '\\', ' ').Replace('\\', '/');
			return new Uri(string.Format("http://dl.dropbox.com/u/{0}/{1}", _userId, path));
		}

		private static long GetUserId(string publicUrl)
		{
			const string pattern = @"http://dl.dropbox.com/u/(\d+)";
			Match match = Regex.Match(publicUrl, pattern, RegexOptions.IgnoreCase);

			if (!match.Success)
				return 0;

			long result;
			long.TryParse(match.Groups[1].Value, out result);
			return result;
		}

		/// <summary>
		/// Checks the file exists or not
		/// </summary>
		/// <param name="url">The URL of the remote file</param>
		/// <returns>True : If the file exits, False if file not exists</returns>
		private static bool RemoteFileExists(string url)
		{
			try
			{
				//Creating the HttpWebRequest
				HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
				request.Timeout = 2000;//timeout in miliseconds
				//Setting the Request method HEAD, you can also use GET too.
				request.Method = "HEAD";
				//Getting the Web Response.
				HttpWebResponse response = request.GetResponse() as HttpWebResponse;
				//Returns TURE if the Status code == 200
				return (response.StatusCode == HttpStatusCode.OK);
			}
			catch (WebException ex)
			{
				System.Diagnostics.Debug.Print(ex.Message);
				//Any exception will returns false.);
				return false;
			}
		}

		public override void SaveImageAsync(Image image, ImageFormat imageFormat, string name, Action<ShotInfo> saveCallback)
		{
			ShotInfo result = base.SaveImage(image, imageFormat, name);

			try
			{
				ThreadPool.QueueUserWorkItem(delegate
				{
					try
					{
						for (int i = 0; i < TRY_UPLOAD_COUNT; i++)
						{
							Thread.Sleep(UPLOAD_SLEEP_TIME);

							if (IsShotInStorege(result, false))
								break;
						}

						saveCallback(result);
					}
					catch (Exception err)
					{
						Trace.WriteLine(err.Message);
					}
				});
			}
			catch (Exception err)
			{
				Trace.WriteLine(err.Message);
			}
		}
	}
}
